// Copyright 2023 Leo <lipf160627@163.com>. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package idGenerator

import (
	"context"

	"github.com/go-redis/redis/v8"
)

type MinIDtor struct {
	redisClient *redis.Client
	name        string
	minID       int64
	maxID       int64
}

// 使用redis bitmap实现ID分配器，总是分配最小的可用ID
// minID 不设置默认为1
// maxID 0 表示不设置最大值
func New(cli *redis.Client, name string, minID, maxID int64) *MinIDtor {
	if cli == nil || name == "" || (maxID != 0 && maxID < minID) {
		return nil
	}

	if minID == 0 {
		minID = 1
	}

	return &MinIDtor{
		redisClient: cli,
		name:        name,
		minID:       minID,
		maxID:       maxID,
	}
}

// 分配一个最小的可用ID
func (idtor *MinIDtor) NewID() int64 {
	minPos, err := idtor.redisClient.BitPos(context.Background(), idtor.name, 0).Result()
	if err != nil {
		return 0
	}

	// out of range
	if idtor.maxID != 0 && minPos > (idtor.maxID-idtor.minID) {
		return 0
	}

	if res, err := idtor.redisClient.SetBit(context.Background(), idtor.name, minPos, 1).Result(); err != nil {
		return 0
	} else {
		if res != 0 {
			return 0
		}
	}

	return minPos + idtor.minID
}

func (idtor *MinIDtor) FreeID(id int64) bool {
	if id < idtor.minID {
		return false
	}

	if idtor.maxID == 0 && id > idtor.maxID {
		return false
	}

	pos := id - idtor.minID

	if _, err := idtor.redisClient.SetBit(context.Background(), idtor.name, pos, 0).Result(); err != nil {
		return false
	}

	return true
}
